Open
Conversation
…e/erase Add rflasher-sunxi-fel crate implementing SPI NOR flash programming through the Allwinner FEL (USB boot) protocol. The programmer uploads a pre-compiled SPI driver payload to the SoC's SRAM and drives SPI via a bytecode protocol, matching xfel's approach. Architecture: - SpiMaster for probe, status registers, write protection, generic SPI - OpaqueMaster for firmware-accelerated bulk read/write (via HybridFlashDevice) - native_erase_block on SpiMaster for on-SoC erase busy-wait Write acceleration (fixes write failure at ~53 KiB): - Batched page programming: ~215 pages per payload execution using SPI_CMD_FAST (WREN) + SPI_CMD_TXBUF (PP data) + SPI_CMD_SPINOR_WAIT (on-SoC busy polling), reducing USB round-trips by ~128x - Previous approach used 3+ separate payload executions per page with host-side status register polling, which failed after ~211 pages Read optimization: - SPI_CMD_FAST embeds small TX data (opcode+address) in the command buffer, eliminating a separate FEL write per 64 KiB chunk - ~7% faster reads (49.7s vs 53.6s for 16 MB on D1/F133) Erase acceleration: - native_erase_block uses SPI_CMD_FAST + SPI_CMD_SPINOR_WAIT for single-execution erase with on-SoC busy-wait Currently supports D1/F133 (RISC-V). Other SoC families need their payload binaries extracted from xfel's chip source files.
Following flashprog's architecture where erase is a first-class operation on the opaque interface (programmers that don't expose raw bus access must provide their own erase), not on the SPI interface (where generic code constructs erase sequences from raw SPI commands). - Remove native_erase_block from SpiMaster trait - HybridFlashDevice::erase() now tries OpaqueMaster::erase() first; falls back to SPI-based WREN+opcode+RDSR polling if it returns Err - SunxiFel::OpaqueMaster::erase() uses FAST+SPINOR_WAIT bytecodes with automatic block size selection (64K/32K/4K) - Dediprog continues to return Err from OpaqueMaster::erase(), triggering the SPI fallback (no behavior change) - SpiFlashDevice::erase() reverted to the original generic path (no native_erase_block concept needed for pure-SPI programmers)
Instead of hardcoding erase opcodes (0xD8/0x52/0x20), SunxiFel now stores the chip's actual erase block table after probing and uses select_erase_block() to pick the correct opcode and block size. This also completes the removal of native_erase_block from SpiMaster. HybridFlashDevice::erase() now tries OpaqueMaster::erase() first (which uses the chip's real erase table + SPINOR_WAIT bytecodes), falling back to SPI-based erase if it returns Err (as Dediprog does). - Re-export select_erase_block from rflasher_core::flash - Add set_erase_blocks() on SunxiFel, called after probe in registry - OpaqueMaster::erase() returns Err if no erase blocks configured, gracefully falling back to the SPI path
- rustfmt: reformat chained method call in hybrid_device.rs - clippy::int_plus_one: simplify cbuf bounds check to < instead of + 1 <= - clippy::manual_div_ceil: use .div_ceil() in round_up_to_mps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
rflasher-sunxi-felcrate implementing SPI NOR flash programming via the Allwinner FEL (USB boot) protocolSPI_CMD_FASTfor small TX dataArchitecture
SunxiFel implements both
SpiMasterandOpaqueMaster, wired throughHybridFlashDevice(same pattern as Dediprog):SpiMasterOpaqueMasterSPI_CMD_FASTfor opcode+addr,RXBUFfor dataOpaqueMasterFAST(WREN) +TXBUF(PP) +SPINOR_WAIT(~215 pages/batch)SpiMaster::native_erase_blockFAST(WREN) +FAST(erase+addr) +SPINOR_WAITWrite fix details
The old approach did 3+ separate FEL payload executions per 256-byte page (WREN, PP, then repeated RDSR polling over USB). This failed after ~211 pages (~53 KiB) due to unreliable host-side status polling.
The new approach matches xfel's
spinor_helper_write: packs ~215 pages into a single command+swap buffer pair and executes the payload once per batch.SPI_CMD_SPINOR_WAIThandles busy-wait on the SoC, eliminating USB round-trips for status polling. This reduces USB transactions by ~128x.Core trait changes
native_erase_block()optional method toSpiMaster(default returnsNone)SpiFlashDevice::erase()andHybridFlashDevice::erase()check it before the generic WREN+erase+RDSR polling pathTest results (D1/F133 + W25Q128, 16 MiB)
The 16 MiB sporadic corruption is a D1/F133 FEL BROM USB reliability issue (xfel hard-errors at 91% on the same test). Not a code bug.
Currently supported SoCs
Other Allwinner families (H2/H3, V3s, F1C100s, R528, H616, etc.) need their SPI payload binaries extracted from xfel's chip source files.